package com.krain.corelibrary.helper.imageloader.depend;

import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.PixelFormat;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.TransitionDrawable;
import android.widget.ImageView;

import com.krain.corelibrary.helper.ImageHelper;
import com.krain.corelibrary.helper.imageloader.ImageLoaderOrigin;
import com.orhanobut.logger.Logger;
import com.krain.corelibrary.http.depend.HttpRequest.HttpRequestException;

import org.apache.http.client.ClientProtocolException;

import java.io.IOException;
import java.lang.ref.WeakReference;
import java.util.WeakHashMap;

/**
 * 由http://developer.android.com/training/displaying-bitmaps/index.html<br>
 * 中BitmapFun.zip demo更改 The actual AsyncTask that will asynchronously process the image.
 */
public class BitmapWorkerTask extends LibAsyncTask<Void, Void, Bitmap> {

    private Context                        mContext;
    private String                         mFilePathOrUrl;
    private LibBitmapDrawable              mLoadingBitmapDrawable; // imageview加载时loading时的图片

    private final WeakReference<ImageView> imageViewReference;

    private boolean                        mFadeInBitmap = true;
    protected Resources                    mResources;
    private static final int               FADE_IN_TIME  = 300;

    private ImageMemCache                  mImageMemCache;
    private DiskLruCache                   mDiskCache;
    private int                            mWidth;
    private int                            mHeight;
    private boolean                        mIsNeedCut;

    private ImageLoaderOrigin.ImageLoaderEvent mImageLoaderEvent;

    public BitmapWorkerTask(String filePathOrUrl, ImageView imageView, Bitmap loadingBitmap,
            ImageMemCache imageMemCache, DiskLruCache diskLruCache, int width, int height, boolean isNeedCut,
            ImageLoaderOrigin.ImageLoaderEvent imageLoaderEvent) {
        this.mFilePathOrUrl = filePathOrUrl;
        mContext = imageView.getContext();
        mResources = mContext.getResources();
        mLoadingBitmapDrawable = new LibBitmapDrawable(mResources, loadingBitmap);
        imageViewReference = new WeakReference<ImageView>(imageView);
        mImageMemCache = imageMemCache;
        mDiskCache = diskLruCache;
        mWidth = width;
        mHeight = height;
        mIsNeedCut = isNeedCut;
        mImageLoaderEvent = imageLoaderEvent;
    }

    /**
     * Background processing.
     */
    final static int Nomal          = 0;
    final static int InSample       = 1;
    final static int InSampleAndCut = 2;

    @Override
    protected Bitmap doInBackground(Void... params) {
        Logger.v("jackzhou", String.format("BitmapWorkerTask-(%s) doInBackground", this.hashCode()));

        if (isCancelled()) {
            return null;
        }

        String memKey = ImageLoaderOrigin.generateMemCacheKey(mFilePathOrUrl, mWidth, mHeight, mIsNeedCut);
        Bitmap temp = mImageMemCache.get(memKey);

        if (temp == null) {// memcache not hit?
            String diskKey = ImageLoaderOrigin.generateDiskCacheKey(mFilePathOrUrl, mWidth, mHeight, mIsNeedCut);
            if(mDiskCache != null){
                temp = mDiskCache.get(diskKey);
            }

            if (temp != null) {// put memcache
                mImageMemCache.put(memKey, temp);
            }
        }

        if (temp == null) {// diskcache not hit?
            try {// load from network
                temp = ImageHelper.getInstance(mContext).loadImage(mFilePathOrUrl, mWidth, mHeight, mIsNeedCut);
            } catch (ClientProtocolException e) {
                temp = null;
                e.printStackTrace();
            } catch (IOException e) {
                temp = null;
                e.printStackTrace();
            } catch (HttpRequestException e) {
                temp = null;
                e.printStackTrace();
            }

            if (temp != null) {// put to cache
                mImageMemCache.put(memKey, temp);
                String diskKey = ImageLoaderOrigin.generateDiskCacheKey(mFilePathOrUrl, mWidth, mHeight, mIsNeedCut);
                if(!temp.isRecycled()&& diskKey != null){//小内存机器极端情况加载大图，直接将图片recycle掉了。mImageMemCache.put(memKey, temp);调用后temp会被recycle
                    mDiskCache.put(diskKey, temp);
                }
            }
        }

        if (temp == null) {
            return null;
        }

        // 将加载中图更改与设置的图一样大，避免显示不一致的问题
        Logger.v(
                "jackzhou",
                String.format("BitmapWorkerTask-(%s) zoomDrawable ->width=%s - height=%s ", this.hashCode(),
                        temp.getWidth(), temp.getHeight()));
        mLoadingBitmapDrawable = (LibBitmapDrawable) zoomDrawable(mLoadingBitmapDrawable, temp.getWidth(),
                temp.getHeight());

        // 仅放入缓存同一内存管理，解决oom问题。不用读取
        String loadingBitmapKey = String.format("%s_%s_%s", mLoadingBitmapDrawable.getBitmap().hashCode(),
                temp.getWidth(), temp.getHeight());
        mImageMemCache.put(loadingBitmapKey, mLoadingBitmapDrawable.getBitmap());

        return temp;
    }

    /**
     * Once the image is processed, associates it to the imageView
     */
    @Override
    protected void onPostExecute(Bitmap bitmap) {
        Logger.v("jackzhou", String.format("BitmapWorkerTask-(%s) ImageLoader.getMTaskQueue() size = %s",
                this.hashCode(), ImageLoaderOrigin.getMTaskQueue().size()));

        if (isCancelled()) {
            bitmap = null;
            // 将自己从队列中remove
            removeFromImageLoader(this);
            return;
        }

        Logger.v("jackzhou", String.format("BitmapWorkerTask-(%s) onPostExecute", this.hashCode()));
        final ImageView imageView = getAttachedImageView();

        if (bitmap != null && imageView != null) {
            setImageBitmap(imageView, bitmap);
        }

        // 完成后将自己从队列中remove
        removeFromImageLoader(this);

        // 处理用户自定义事件
        if (mImageLoaderEvent != null && imageView != null) {
            mImageLoaderEvent.onImageFinish(imageView, bitmap);
        }
    }

    @Override
    protected void onCancelled() {
        super.onCancelled();
    }

    @Override
    protected void onCancelled(Bitmap result) {

    }

    /**
     * Returns the ImageView associated with this task as long as the ImageView's task still points to this task as well. Returns null otherwise.
     */
    private ImageView getAttachedImageView() {
        final ImageView imageView = imageViewReference.get();
        final BitmapWorkerTask bitmapWorkerTask = getBitmapWorkerTask(imageView);

        if (this == bitmapWorkerTask) {
            return imageView;
        }

        return null;
    }

    /**
     * Called when the processing is complete and the final bitmap should be set on the ImageView.
     * 
     * @param imageView
     * @param bitmap
     */
    private void setImageBitmap(ImageView imageView, Bitmap bitmap) {
        if (mFadeInBitmap) {
            final TransitionDrawable td = new TransitionDrawable(new Drawable[] { mLoadingBitmapDrawable,
                    new LibBitmapDrawable(mResources, bitmap) });

            // Set background to loading bitmap
            // imageView.setBackgroundDrawable(new BitmapDrawable(mResources,
            // mLoadingBitmap));
            // 更改效果，使用setImageDrawable.setBackgroundDrawable在放小图片时，背景图会露出来。
            // imageView.setImageDrawable(mLoadingBitmapDrawable);
            imageView.setImageDrawable(td);
            td.startTransition(FADE_IN_TIME);
        } else {
            imageView.setImageDrawable(new LibBitmapDrawable(mContext.getResources(), bitmap));
        }
    }

    private Bitmap drawableToBitmap(Drawable drawable) {// drawable 转换成 bitmap
        int width = drawable.getIntrinsicWidth(); // 取 drawable 的长宽
        int height = drawable.getIntrinsicHeight();
        Bitmap.Config config = drawable.getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888
                : Bitmap.Config.RGB_565; // 取 drawable 的颜色格式
        Bitmap bitmap = Bitmap.createBitmap(width, height, config); // 建立对应
                                                                    // bitmap
        Logger.v("jackzhou", String.format("loadingbitmap - create new bitmap: %s", String.valueOf(bitmap)));
        Canvas canvas = new Canvas(bitmap); // 建立对应 bitmap 的画布
        drawable.setBounds(0, 0, width, height);
        drawable.draw(canvas); // 把 drawable 内容画到画布中
        return bitmap;
    }

    private LibBitmapDrawable zoomDrawable(Drawable drawable, int w, int h) {
        int width = drawable.getIntrinsicWidth();
        int height = drawable.getIntrinsicHeight();
        Bitmap oldbmp = drawableToBitmap(drawable); // drawable 转换成 bitmap
        Matrix matrix = new Matrix(); // 创建操作图片用的 Matrix 对象
        float scaleWidth = ((float) w / width); // 计算缩放比例
        float scaleHeight = ((float) h / height);
        matrix.postScale(scaleWidth, scaleHeight); // 设置缩放比例
        Bitmap newbmp = Bitmap.createBitmap(oldbmp, 0, 0, width, height, matrix, true); // 建立新的
                                                                                        // bitmap
                                                                                        // ，其内容是对原
                                                                                        // bitmap
                                                                                        // 的缩放后的图
        Logger.v("jackzhou", String.format("loadingbitmap - create new bitmap: %s", String.valueOf(newbmp)));

        // 回收bitmap 防止oom
        Logger.v("jackzhou", String.format("loadingbitmap  zoomDrawable - recycle bitmap: %s", String.valueOf(oldbmp)));
        oldbmp.recycle();
        oldbmp = null;

        return new LibBitmapDrawable(mContext.getResources(), newbmp);
    }

    /**
     * @param imageView
     *            Any imageView
     * @return Retrieve the currently active work task (if any) associated with this imageView. null if there is no such task.
     */
    private static BitmapWorkerTask getBitmapWorkerTask(ImageView imageView) {
        if (imageView != null) {
            final Drawable drawable = imageView.getDrawable();
            if (drawable instanceof AsyncDrawable) {
                final AsyncDrawable asyncDrawable = (AsyncDrawable) drawable;
                return asyncDrawable.getBitmapWorkerTask();
            }
        }
        return null;
    }

    /**
     * Returns true if the current work has been canceled or if there was no work in progress on this image view. Returns false if the work in progress deals
     * with the same data. The work is not stopped in that case.
     */
    public static boolean cancelPotentialWork(String mFilePathOrUrl, ImageView imageView) {
        final BitmapWorkerTask bitmapWorkerTask = getBitmapWorkerTask(imageView);

        if (bitmapWorkerTask != null) {
            final String bitmapUrl = bitmapWorkerTask.mFilePathOrUrl;
            if (bitmapUrl == null || !bitmapUrl.equals(mFilePathOrUrl)) {
                bitmapWorkerTask.cancel(true);
                // 将任务从队列中remove
                removeFromImageLoader(bitmapWorkerTask);
            } else {
                // The same work is already in progress.
                return false;
            }
        }
        return true;
    }

    /**
     * 设置图片显示 是否有FadeIn效果
     * 
     * @param isFadeInBitmap
     */
    public void setIsFadeInBitmap(boolean isFadeInBitmap) {
        mFadeInBitmap = isFadeInBitmap;
    }

    /**
     * 将自己从imageloader队列中移除
     */
    private static void removeFromImageLoader(BitmapWorkerTask bitmapWorkerTask) {
        WeakHashMap<BitmapWorkerTask, BitmapWorkerTask> allTask = ImageLoaderOrigin.getMTaskQueue();

        if (allTask == null) {
            return;
        }

        BitmapWorkerTask temp = allTask.get(bitmapWorkerTask);
        if (temp != null) {
            synchronized (allTask) {
                allTask.remove(temp);
            }
        }
    }
}
